#ifndef JLINKARM_H
#define JLINKARM_H

#ifdef __cplusplus
extern "C" {  
#endif


#include "windows.h"
#include <stdint.h>



#define log_(format,...) printf(format,##__VA_ARGS__)
#define logE(format,...) printf("[E] "format"\n",##__VA_ARGS__)
#define logW(format,...) printf("[W] "format"\n",##__VA_ARGS__)
#define logI(format,...) printf("[I] "format"\n",##__VA_ARGS__)
#define logD(format,...) printf("[D] "format"\n",##__VA_ARGS__)


//JLINK TIF
#define JLINKARM_TIF_JTAG          0
#define JLINKARM_TIF_SWD           1
 
//RESET TYPE
#define JLINK_RESET_TYPE_NORMAL 0
#define JLINK_RESET_TYPE_CORE   1
#define JLINK_RESET_TYPE_PIN    2

//
#define JLINKARM_RTTERMINAL_CMD_START     0 //Starts RTT processing. This includes background read of RTT data from target. p may be NULL.
#define JLINKARM_RTTERMINAL_CMD_STOP      1 //Stops RTT on the J-Link and host side. p may be NULL.
#define JLINKARM_RTTERMINAL_CMD_GETNUMBUF 2 //After starting RTT, get the current number of up or down buffers.
#define JLINKARM_RTTERMINAL_CMD_GETDESC   3 //Get the size, name, and flag of a buffer.

//REGISTER INDEX
/* 
  0 - 15     R0 - R15(SP=R13, PC=R15)
 16          XPSR
 17          MSP
 18          PSP
 19          RAZ
 20          CFBP
 21          APSR
 22          EPSR
 23          IPSR
 24          PRIMASK
 25          BASEPRI
 26          FAULTMASK
 27          CONTROL 
 28          BASEPRI_MAX
 29          IAPSR
 30          EAPSR
 31          IEPSR
 */
typedef int8_t i8;
typedef uint8_t u8;
typedef int8_t I8;
typedef uint8_t U8;
typedef int16_t i16;
typedef uint16_t u16;
typedef int16_t I16;
typedef uint16_t U16;
typedef int32_t i32;
typedef uint32_t u32;
typedef int32_t I32;
typedef uint32_t U32;
typedef int64_t i64;
typedef uint64_t u64;
typedef int64_t I64;
typedef uint64_t U64;


typedef struct {
 U32 HostIF; // Host interface used to connect to J-Link.
 // 0 = USB, 1 = IP
 U32 TargetIF; // See JLINKARM_Const.h "Interfaces" for valid values
 U32 SerialNo; 
 // Serial number of J-Link we want to connect to via USB
 U32 Speed; // Interface speed in kHz
 const char* sHost; // Points to the IPAddr / nickname of the J-Link
 // we want to connect to.
 const char* sSettingsFile;
 const char* sDevice; // Target device J-Link is connected to
 const char* sScriptFile;
 // J-Link script file to perform special connect etc.
} INIT_PARAS;

typedef void (JLINKARM_LOG)(const char* log);

extern void     (*JLINKARM_SetLogFile)(const char *file);
extern u32      (*JLINKARM_GetDLLVersion)(void);
extern i32      (*JLINKARM_GetHardwareVersion)(void);
extern void     (*JLINKARM_GetFirmwareString)(char *buffer, int BufferSize);
/**
 * Returns the serial number of the connected J-Link or an Error code if an error occurred.
 * >=0 Serial number
 * <0 Error
*/
extern i32      (*JLINKARM_GetSN)(void); 

extern i32      (*JLINKARM_ExecCommand)(const char*cmd, char* sError, int BufferSize);
extern i32      (*JLINKARM_TIF_Select)(int Interface);
extern void     (*JLINKARM_SetSpeed)(uint32_t Speed);
extern u16      (*JLINKARM_GetSpeed)(void);
extern u32      (*JLINKARM_GetId)(void);
extern i32      (*JLINKARM_GetDeviceFamily)(void); 
/**
 * return:
 * NULL ok
 * !=NULL Error string

*/
extern const char* (*JLINKARM_Open)(void);
/**
 * @brief
 *pfLog:
        Pointer to log handler function of type JLINKARM_LOG.
  pfErrorOut:
        Pointer to error out handler function of type JLINKARM_LOG.
 * return:
 * NULL ok
 * !=NULL Error string

*/
extern const char* (*JLINKARM_OpenEx)(JLINKARM_LOG *pfLog, JLINKARM_LOG *pfErrorOut);

extern void     (*JLINKARM_Close)(void);
extern char     (*JLINKARM_IsOpen)(void); 
/**
 * >=0 ok 
 * <0 Error
*/
extern int      (*JLINKARM_Connect)(void);
/**
 * 1 connected
 * 0 not connected
*/
extern i8       (*JLINKARM_IsConnected)(void);
// extern i8       (*JLINKARM_EMU_IsConnected)(void);
// extern i8       (*JLINKARM_Halt)(void);
// extern i8       (*JLINKARM_IsHalted)(void);
// extern void     (*JLINKARM_SetResetType)(int reset_type);
extern i32      (*JLINKARM_Reset)(void);

// extern void  (*JLINK_Go)(void);
// extern void  (*JLINK_GoIntDis)(void);
extern u32      (*JLINKARM_ReadReg)(int RegIndex);
extern i8       (*JLINKARM_WriteReg)(int RegIndex, u32 data); 

/**
 * 0 ok
 * 1 Error
*/
extern i32      (*JLINKARM_ReadMem)(u32 addr, u32 NumBytes, void *pData);
extern i32      (*JLINKARM_ReadMemHW)(u32 addr, u32 NumBytes, void *pData);

/**
 * >=0 ok
 * <0 Error
*/
extern int   (*JLINKARM_WriteMem)(u32 addr, u32 count, void* data);
/**
 * =0 ok
 * !=0 Error
*/
extern int   (*JLINK_WriteU8)(u32 addr, u16 data);
extern int   (*JLINK_WriteU16)(u32 addr, u16 data);
extern int   (*JLINK_WriteU32)(u32 addr, u32 data); 

/**
 * >=0 ok
 * <0 Error
*/
extern int   (*JLINK_EraseChip)(void);
/**
 * Flags: Reserved for future use. Set to 0.
*/
extern void  (*JLINKARM_BeginDownload)(u32 Flags);
/**
 * This function programs a given data file to a specified destination address.
Currently supported data files are:
? *.mot
? *.srec
? *.s19
? *.s
? *.hex
? *.bin
return:
 * >=0 ok
 * <0 Error
*/
extern int   (*JLINK_DownloadFile)(const char* sFileName, u32 addr);
/**
 * >=0 Numberofprogrammedbytes.
Might be different from the num-
berofbytesinitiallywrittenvia
multiple calls of JLINKARM_Write-Mem() since the DLL optimizes
flash download and only programsthenecessaryranges.If
somerangesarealreadyprogrammed with the correct data,programmingfortheserangesis skipped.
  <0 Error
*/
extern int  (*JLINKARM_EndDownload)(void);
/**
 * >=0 ok
 * <0 Error

*/
extern int  (*JLINKARM_EMU_SelectByUSBSN)(U32 SerialNo);
/**
 * 
 * port: USB port to be used for the connection. Valid values range from 0 to 3
 * return:
 * 0 ok
 * 1 Error
*/
extern int  (*JLINKARM_SelectUSB)(int port);
/**
 * 0 ok
 * 1 Error
*/
extern int  (*JLINKARM_SelectIP)(const char* sHost, int Port);

extern void (*JLINKARM_Go)(void);

/**
 * @brief Writes data into the RTT buffer.
 * @return
 * >=0 ok, number of bytes written.
 * <0 Error
*/
extern int JLINK_RTTERMINAL_Write(u32 BufferIndex, const char* sBuffer, u32 BufferSize);
/**
 * @brief Reads bytes from the RTT host-side buffer.
 * @return
 * >=0 ok  , number of bytes read.
 * <0 Error
*/
extern int JLINK_RTTERMINAL_Read(u32 BufferIndex, char* sBuffer, u32 BufferSize);
/**
 * @brief Calls an internal command to control RTT.
 * @var Cmd:  The Cmd that should be executed
 *            JLINKARM_RTTERMINAL_CMD_START: Starts RTT
 *           JLINKARM_RTTERMINAL_CMD_STOP: Stops RTT
 *           JLINKARM_RTTERMINAL_CMD_GETDESC: Returns the RTT Control Block address and size.
 *           JLINKARM_RTTERMINAL_CMD_GETNUMBUF: Returns the number of RTT buffers.
 * @var p:    Pointer to structure containing parameters for the command.
 * @return 
 *  >=0 success
 * <0 Error
 * 0: Cmd = JLINKARM_RTTERMINAL_CMD_STOP: RTT was running and has been stopped r
 * 1: Cmd = JLINKARM_RTTERMINAL_CMD_STOP: RTT stopped but was not running before
 * -2:If CMD = (JLINKARM_RTTERMINAL_CMD_GETDESC || JLINKARM_RTTERMINAL_CMD_GETNUMBUF):RTT Control Block not found yet.
*/
extern int JLINK_RTTERMINAL_Control(u32 Cmd, void* p);

/**
 * app must init jlinkarm by this function
*/
extern int _InitDebugSession(INIT_PARAS *pParas);
int program_bin_file(const char *filename, u32 addr);

#ifdef __cplusplus
}
#endif

#endif // JLINKARM_H
